﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace OCR
{

    /// <summary>
    /// 图片处理接口
    /// </summary>
    public interface IPictureProcess
    {
        Bitmap Process();
    }

    /// <summary>
    /// 图片灰度
    /// </summary>
    public class PictureToGray : IPictureProcess
    {
        /// <summary>
        /// 像素法
        /// </summary>
        /// <param name="curBitmap"></param>
        private void PixelFun(Bitmap curBitmap)
        {
            int width = curBitmap.Width;
            int height = curBitmap.Height;
            for (int i = 0; i < width; i++) //这里如果用i<curBitmap.Width做循环对性能有影响
            {
                for (int j = 0; j < height; j++)
                {
                    Color curColor = curBitmap.GetPixel(i, j);
                    int ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
                    curBitmap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
                }
            }
        }
        /// <summary>
        /// 内存拷贝法
        /// </summary>
        /// <param name="curBitmap"></param>
        private unsafe void MemoryCopy(Bitmap curBitmap)
        {
            int width = curBitmap.Width;
            int height = curBitmap.Height;

            Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
            System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//curBitmap.PixelFormat

            IntPtr ptr = bmpData.Scan0;
            int bytesCount = bmpData.Stride * bmpData.Height;
            byte[] arrDst = new byte[bytesCount];
            Marshal.Copy(ptr, arrDst, 0, bytesCount);

            for (int i = 0; i < bytesCount; i += 3)
            {
                byte colorTemp = (byte)(arrDst[i + 2] * 0.299 + arrDst[i + 1] * 0.587 + arrDst[i] * 0.114);
                arrDst[i] = arrDst[i + 1] = arrDst[i + 2] = (byte)colorTemp;

            }
            Marshal.Copy(arrDst, 0, ptr, bytesCount);
            curBitmap.UnlockBits(bmpData);
        }
        /// <summary>
        /// 指针法
        /// </summary>
        /// <param name="curBitmap"></param>
        private unsafe void PointerFun(Bitmap curBitmap)
        {
            int width = curBitmap.Width;
            int height = curBitmap.Height;

            Rectangle rect = new Rectangle(0, 0, curBitmap.Width, curBitmap.Height);
            System.Drawing.Imaging.BitmapData bmpData = curBitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//curBitmap.PixelFormat
            byte temp = 0;
            int w = bmpData.Width;
            int h = bmpData.Height;
            byte* ptr = (byte*)(bmpData.Scan0);
            for (int i = 0; i < h; i++)
            {
                for (int j = 0; j < w; j++)
                {
                    temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);
                    ptr[0] = ptr[1] = ptr[2] = temp;
                    ptr += 3; //Format24bppRgb格式每个像素占3字节
                }
                ptr += bmpData.Stride - bmpData.Width * 3;//每行读取到最后“有用”数据时，跳过未使用空间XX
            }
            curBitmap.UnlockBits(bmpData);
        }
        private Bitmap picture;

        public PictureToGray(Bitmap picture)
        {
            this.picture = picture;
        }
        public Bitmap Process()
        {
            return BitmapHelper.ToGrayBitmap(picture);
        }
    }

    /// <summary>
    /// 图片二值化
    /// </summary>
    public class PictureToBinary : IPictureProcess
    {
        private Bitmap picture;
        private int threshold;
        public PictureToBinary(Bitmap picture, int threshold)
        {
            this.picture = picture;
            this.threshold = threshold;
        }
        public Bitmap Process()
        {
            return BitmapHelper.ToGrayBitmap(picture);
        }
    }
    public static class BitmapHelper
    {
        /// <summary>
        /// 裁剪并处理（二值化、去噪点)处理图片
        /// </summary>
        /// <param name="fromImage"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Bitmap CutProcessImage(Bitmap fromImage, Rectangle rect, BinarizationMethods twoMothod, bool noiseClear)
        {
            Bitmap cutImage = new Bitmap(rect.Width, rect.Height);
            using (Graphics graphic = Graphics.FromImage(cutImage))
            {
                //清空画布并以透明背景色填充
                graphic.Clear(Color.Transparent);
                //在指定位置并且按指定大小绘制原图片的指定部分
                graphic.DrawImage(fromImage, 0, 0, rect, GraphicsUnit.Pixel);
                //灰度化
                cutImage = BitmapHelper.ToGrayBitmap(cutImage);
                int value;
                //二值化
                cutImage = BitmapHelper.ToBinaryBitmap(cutImage, twoMothod, out value);
                Bitmap pzImage = cutImage.Clone(new Rectangle(0, 0, cutImage.Width, cutImage.Height), PixelFormat.Format24bppRgb);
                //膨胀
               // cutImage = BitmapHelper.GetPengZhangImage(pzImage);
                //  return cutImage;
                if (noiseClear)
                {
                    Bitmap toImage = cutImage.Clone(new Rectangle(0, 0, cutImage.Width, cutImage.Height), PixelFormat.Format24bppRgb);
                    //去噪点
                    BitmapHelper.ClearNoise(value, toImage);
                    return toImage;
                }
                else
                {
                    return cutImage;
                }
            }
        }

        /// <summary>
        /// 膨胀算法
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public static Bitmap GetPengZhangImage(Bitmap image)
        {
            List<Point> setList = new List<Point>();

            Bitmap result = image.Clone() as Bitmap;

            for (int i = 0; i < result.Width; i++)
            {
                for (int j = 0; j < result.Height; j++)
                {
                    // 如果应该设置为黑色的
                    if (SetPixelPengZhang(result, i, j))
                    {
                        setList.Add(new Point(i, j));
                    }
                }
            }

            int x, y;
            foreach (var item in setList)
            {
                x = item.X;
                y = item.Y;

                if (x + 1 < image.Width && y + 1 < image.Height)
                {


                    result.SetPixel(x - 1, y - 1, Color.Black);
                    result.SetPixel(x, y - 1, Color.Black);
                    result.SetPixel(x + 1, y - 1, Color.Black);
                    result.SetPixel(x + 1, y, Color.Black);
                    result.SetPixel(x + 1, y + 1, Color.Black);
                    result.SetPixel(x, y + 1, Color.Black);
                    result.SetPixel(x - 1, y + 1, Color.Black);
                    result.SetPixel(x - 1, y, Color.Black);
                }
            }
            return result;
        }

        // 判断这个点应不应该设置为黑色
        public static bool SetPixelPengZhang(Bitmap image, int i, int j)
        {
            Color c = image.GetPixel(i, j);

            if (i != 0 && j != 0)
            {
                if (image.GetPixel(i, j).ToArgb() == Color.Black.ToArgb())
                {
                    return true;
                }
                else return false;
            }
            else return false;
        }
        /// <summary>
        /// 腐蚀（来消除小且无意义的物体）
        /// </summary>
        /// <param name="image">二值化图片</param>
        /// <returns></returns>
        public static Bitmap GetFuShiImage(Bitmap image)
        {
            List<Point> setList = new List<Point>();

            Bitmap result = image.Clone() as Bitmap;

            for (int i = 0; i < result.Width; i++)
            {
                for (int j = 0; j < result.Height; j++)
                {
                    // 如果是应该设置为黑色的点，将其添加到我们要设的list中
                    if (SetPixelFuShi(result, i, j))
                    {
                        setList.Add(new Point(i, j));
                    }
                }
            }

            // 遍历，设置相应的值
            foreach (var item in setList)
            {
                result.SetPixel(item.X, item.Y, Color.White);
            }

            return result;
        }

        // 判断一个点是不是应该设置为白颜色
        public static bool SetPixelFuShi(Bitmap image, int i, int j)
        {
            int origion;
            int upPoint;
            int leftPoint;

            if (i != 0 && j != 0)
            {
                origion = image.GetPixel(i, j).ToArgb();
                upPoint = image.GetPixel(i, j - 1).ToArgb();
                leftPoint = image.GetPixel(i - 1, j).ToArgb();

                // image.GetPixel(i,j) == Color.Black
                // 这样写居然没用，我还调试了老半天，也不报错！！！
                if (origion == Color.Black.ToArgb() &&
                   upPoint == Color.Black.ToArgb() &&
                   leftPoint == Color.Black.ToArgb())
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
            else return true;
        }

        /// <summary>
        /// 位图灰度化
        /// </summary>
        /// <param name="bmp">原始位图</param>
        /// <returns>灰度位图</returns>
        public static Bitmap ToGrayBitmap(this Bitmap bmp)
        {
            Int32 PixelHeight = bmp.Height; // 图像高度
            Int32 PixelWidth = bmp.Width;   // 图像宽度
            Int32 Stride = ((PixelWidth * 3 + 3) >> 2) << 2;    // 跨距宽度
            Byte[] Pixels = new Byte[PixelHeight * Stride];

            // 锁定位图到系统内存
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, PixelWidth, PixelHeight), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            Marshal.Copy(bmpData.Scan0, Pixels, 0, Pixels.Length);  // 从非托管内存拷贝数据到托管内存
            bmp.UnlockBits(bmpData);    // 从系统内存解锁位图

            // 将像素数据转换为灰度数据
            Int32 GrayStride = ((PixelWidth + 3) >> 2) << 2;
            Byte[] GrayPixels = new Byte[PixelHeight * GrayStride];
            for (Int32 i = 0; i < PixelHeight; i++)
            {
                Int32 Index = i * Stride;
                Int32 GrayIndex = i * GrayStride;
                for (Int32 j = 0; j < PixelWidth; j++)
                {
                    GrayPixels[GrayIndex++] = Convert.ToByte((Pixels[Index + 2] * 19595 + Pixels[Index + 1] * 38469 + Pixels[Index] * 7471 + 32768) >> 16);
                    Index += 3;
                }
            }

            // 创建灰度图像
            Bitmap GrayBmp = new Bitmap(PixelWidth, PixelHeight, PixelFormat.Format8bppIndexed);

            // 设置调色表
            ColorPalette cp = GrayBmp.Palette;
            for (int i = 0; i < 256; i++) cp.Entries[i] = Color.FromArgb(i, i, i);
            GrayBmp.Palette = cp;

            // 设置位图图像特性
            BitmapData GrayBmpData = GrayBmp.LockBits(new Rectangle(0, 0, PixelWidth, PixelHeight), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
            Marshal.Copy(GrayPixels, 0, GrayBmpData.Scan0, GrayPixels.Length);
            GrayBmp.UnlockBits(GrayBmpData);

            return GrayBmp;
        }

        /// <summary>
        /// 全局阈值图像二值化
        /// </summary>
        /// <param name="bmp">原始图像</param>
        /// <param name="method">二值化方法</param>
        /// <param name="threshold">输出：全局阈值</param>
        /// <returns>二值化图像</returns>
        public static Bitmap ToBinaryBitmap(this Bitmap bmp, BinarizationMethods method, out Int32 threshold)
        {   // 位图转换为灰度数组
            Byte[,] GrayArray = bmp.ToGrayArray();

            // 计算全局阈值
            if (method == BinarizationMethods.Otsu)
                threshold = OtsuThreshold(GrayArray);
            else
                threshold = IterativeThreshold(GrayArray);

            // 将灰度数组转换为二值数据
            Int32 PixelHeight = bmp.Height;
            Int32 PixelWidth = bmp.Width;
            Int32 Stride = ((PixelWidth + 31) >> 5) << 2;
            Byte[] Pixels = new Byte[PixelHeight * Stride];
            for (Int32 i = 0; i < PixelHeight; i++)
            {
                Int32 Base = i * Stride;
                for (Int32 j = 0; j < PixelWidth; j++)
                {
                    if (GrayArray[i, j] > threshold)
                    {
                        Pixels[Base + (j >> 3)] |= Convert.ToByte(0x80 >> (j & 0x7));
                    }
                }
            }

            // 从二值数据中创建黑白图像
            Bitmap BinaryBmp = new Bitmap(PixelWidth, PixelHeight, PixelFormat.Format1bppIndexed);

            // 设置调色表
            ColorPalette cp = BinaryBmp.Palette;
            cp.Entries[0] = Color.Black;    // 黑色
            cp.Entries[1] = Color.White;    // 白色
            BinaryBmp.Palette = cp;

            // 设置位图图像特性
            BitmapData BinaryBmpData = BinaryBmp.LockBits(new Rectangle(0, 0, PixelWidth, PixelHeight), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
            Marshal.Copy(Pixels, 0, BinaryBmpData.Scan0, Pixels.Length);
            BinaryBmp.UnlockBits(BinaryBmpData);

            return BinaryBmp;
        }
        /// <summary>
        /// 大津法计算阈值
        /// </summary>
        /// <param name="grayArray">灰度数组</param>
        /// <returns>二值化阈值</returns> 
        private static Int32 OtsuThreshold(Byte[,] grayArray)
        {   // 建立统计直方图
            Int32[] Histogram = new Int32[256];
            Array.Clear(Histogram, 0, 256);     // 初始化
            foreach (Byte b in grayArray)
            {
                Histogram[b]++;                 // 统计直方图
            }

            // 总的质量矩和图像点数
            Int32 SumC = grayArray.Length;    // 总的图像点数
            Double SumU = 0;                  // 双精度避免方差运算中数据溢出
            for (Int32 i = 1; i < 256; i++)
            {
                SumU += i * Histogram[i];     // 总的质量矩                
            }

            // 灰度区间
            Int32 MinGrayLevel = Array.FindIndex(Histogram, NonZero);       // 最小灰度值
            Int32 MaxGrayLevel = Array.FindLastIndex(Histogram, NonZero);   // 最大灰度值

            // 计算最大类间方差
            Int32 Threshold = MinGrayLevel;
            Double MaxVariance = 0.0;       // 初始最大方差
            Double U0 = 0;                  // 初始目标质量矩
            Int32 C0 = 0;                   // 初始目标点数
            for (Int32 i = MinGrayLevel; i < MaxGrayLevel; i++)
            {
                if (Histogram[i] == 0) continue;

                // 目标的质量矩和点数                
                U0 += i * Histogram[i];
                C0 += Histogram[i];

                // 计算目标和背景的类间方差
                Double Diference = U0 * SumC - SumU * C0;
                Double Variance = Diference * Diference / C0 / (SumC - C0); // 方差
                if (Variance > MaxVariance)
                {
                    MaxVariance = Variance;
                    Threshold = i;
                }
            }

            // 返回类间方差最大阈值
            return Threshold;
        }
        /// <summary>
        /// 迭代法计算阈值
        /// </summary>
        /// <param name="grayArray">灰度数组</param>
        /// <returns>二值化阈值</returns> 
        private static Int32 IterativeThreshold(Byte[,] grayArray)
        {   // 建立统计直方图
            Int32[] Histogram = new Int32[256];
            Array.Clear(Histogram, 0, 256);     // 初始化
            foreach (Byte b in grayArray)
            {
                Histogram[b]++;                 // 统计直方图
            }

            // 总的质量矩和图像点数
            Int32 SumC = grayArray.Length;    // 总的图像点数
            Int32 SumU = 0;
            for (Int32 i = 1; i < 256; i++)
            {
                SumU += i * Histogram[i];     // 总的质量矩                
            }

            // 确定初始阈值
            Int32 MinGrayLevel = Array.FindIndex(Histogram, NonZero);       // 最小灰度值
            Int32 MaxGrayLevel = Array.FindLastIndex(Histogram, NonZero);   // 最大灰度值
            Int32 T0 = (MinGrayLevel + MaxGrayLevel) >> 1;
            if (MinGrayLevel != MaxGrayLevel)
            {
                for (Int32 Iteration = 0; Iteration < 100; Iteration++)
                {   // 计算目标的质量矩和点数
                    Int32 U0 = 0;
                    Int32 C0 = 0;
                    for (Int32 i = MinGrayLevel; i <= T0; i++)
                    {   // 目标的质量矩和点数                
                        U0 += i * Histogram[i];
                        C0 += Histogram[i];
                    }

                    // 目标的平均灰度值和背景的平均灰度值的中心值
                    Int32 T1 = (U0 / C0 + (SumU - U0) / (SumC - C0)) >> 1;
                    if (T0 == T1) break; else T0 = T1;
                }
            }

            // 返回最佳阈值
            return T0;
        }

        /// <summary>
        /// 检测非零值
        /// </summary>
        /// <param name="value">要检测的数值</param>
        /// <returns>
        ///     true：非零
        ///     false：零
        /// </returns>
        private static Boolean NonZero(Int32 value)
        {
            return (value != 0) ? true : false;
        }

        // 滤波算法去噪函数
        // 图像预处理中有多种滤波算法，其原理与方法分别为
        // 1） 中值滤波
        //它通过从图像中的某个采样窗口取出奇数个数据进行排序得到的结果。顾名思义，所谓中值就是窗口中奇数个数据按大小顺序排列后处于中心位置的那个数。中值滤波以窗口的中值作为处理结果。
        //实现起来很简单
        //1：先对窗口排序
        //2：用排序后的中值取代要处理的数据即可
        //注意事项：
        //1：注意图像边缘数据的处理
        //2：对于不同的目的选用不同的窗体，一般有3×3，5×5等等
        /// <summary>
        /// 3×3中值滤波除杂
        /// </summary>
        /// <param name="dgGrayValue"></param>
        public static void ClearNoise(int dgGrayValue, Bitmap bmpobj)
        {
            int x, y;
            byte[] p = new byte[9]; //最小处理窗口3*3
            byte s;
            //byte[] lpTemp=new BYTE[nByteWidth*nHeight];
            int i, j;

            //--!!!!!!!!!!!!!!下面开始窗口为3×3中值滤波!!!!!!!!!!!!!!!!
            for (y = 1; y < bmpobj.Height - 1; y++) //--第一行和最后一行无法取窗口
            {
                for (x = 1; x < bmpobj.Width - 1; x++)
                {
                    //取9个点的值
                    p[0] = bmpobj.GetPixel(x - 1, y - 1).R;
                    p[1] = bmpobj.GetPixel(x, y - 1).R;
                    p[2] = bmpobj.GetPixel(x + 1, y - 1).R;
                    p[3] = bmpobj.GetPixel(x - 1, y).R;
                    p[4] = bmpobj.GetPixel(x, y).R;
                    p[5] = bmpobj.GetPixel(x + 1, y).R;
                    p[6] = bmpobj.GetPixel(x - 1, y + 1).R;
                    p[7] = bmpobj.GetPixel(x, y + 1).R;
                    p[8] = bmpobj.GetPixel(x + 1, y + 1).R;
                    //计算中值
                    for (j = 0; j < 5; j++)
                    {
                        for (i = j + 1; i < 9; i++)
                        {
                            if (p[j] > p[i])
                            {
                                s = p[j];
                                p[j] = p[i];
                                p[i] = s;
                            }
                        }
                    }
                    //      if (bmpobj.GetPixel(x, y).R < dgGrayValue)
                    bmpobj.SetPixel(x, y, Color.FromArgb(p[4], p[4], p[4]));    //给有效值付中值
                }
            }
        }

        public static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }
        /// <summary>
        /// 压缩保存图片
        /// </summary>
        /// <param name="bimmap"></param>
        public static void SaveSmallImage(Bitmap bitmap, string fileFullName)
        {
            //压缩保存原图
            ImageCodecInfo myImageCodecInfo = BitmapHelper.GetEncoderInfo("image/jpeg");
            System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
            EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 25L);
            EncoderParameters myEncoderParameters = new EncoderParameters(1);
            myEncoderParameters.Param[0] = myEncoderParameter;
            bitmap.Save(fileFullName, myImageCodecInfo, myEncoderParameters);
        }

        /// <summary>
        /// 图像灰度化
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        public static Bitmap ToGray(Bitmap bmp)
        {
            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    //获取该点的像素的RGB的颜色
                    Color color = bmp.GetPixel(i, j);
                    //利用公式计算灰度值
                    int gray = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
                    Color newColor = Color.FromArgb(gray, gray, gray);
                    bmp.SetPixel(i, j, newColor);
                }
            }
            return bmp;
        }
        /// <summary>
        /// 图像灰度反转
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        public static Bitmap GrayReverse(Bitmap bmp)
        {
            for (int i = 0; i < bmp.Width; i++)
            {
                for (int j = 0; j < bmp.Height; j++)
                {
                    //获取该点的像素的RGB的颜色
                    Color color = bmp.GetPixel(i, j);
                    Color newColor = Color.FromArgb(255 - color.R, 255 - color.G, 255 - color.B);
                    bmp.SetPixel(i, j, newColor);
                }
            }
            return bmp;
        }
        /// <summary>
        /// 图像二值化1：取图片的平均灰度作为阈值，低于该值的全都为0，高于该值的全都为255
        /// </summary>
        /// <param name="grayBitmap"></param>
        /// <returns></returns>
        public static Bitmap GrayToBinary(Bitmap grayBitmap)
        {
            int average = 0;
            for (int i = 0; i < grayBitmap.Width; i++)
            {
                for (int j = 0; j < grayBitmap.Height; j++)
                {
                    Color color = grayBitmap.GetPixel(i, j);
                    average += color.B;
                }
            }
            average = (int)average / (grayBitmap.Width * grayBitmap.Height);

            for (int i = 0; i < grayBitmap.Width; i++)
            {
                for (int j = 0; j < grayBitmap.Height; j++)
                {
                    //获取该点的像素的RGB的颜色
                    Color color = grayBitmap.GetPixel(i, j);
                    int value = 255 - color.B;
                    Color newColor = value > average ? Color.FromArgb(0, 0, 0) : Color.FromArgb(255,

  255, 255);
                    grayBitmap.SetPixel(i, j, newColor);
                }
            }
            return grayBitmap;
        }

        /// <summary>
        /// 图形细化
        /// </summary>
        /// <param name="srcImg"></param>
        /// <returns></returns>
        public static unsafe Bitmap ToThinner(Bitmap srcImg)
        {
            int iw = srcImg.Width;
            int ih = srcImg.Height;
            bool bModified;     //二值图像修改标志            
            bool bCondition1;   //细化条件1标志            
            bool bCondition2;   //细化条件2标志            
            bool bCondition3;   //细化条件3标志            
            bool bCondition4;   //细化条件4标志
            int nCount;
            //5X5像素块            
            byte[,] neighbour = new byte[5, 5];
            //新建临时存储图像            
            Bitmap NImg = new Bitmap(iw, ih, srcImg.PixelFormat);
            bModified = true;
            //细化修改标志, 用作循环条件
            BitmapData dstData = srcImg.LockBits(new Rectangle(0, 0, iw, ih), ImageLockMode.ReadWrite, srcImg.PixelFormat);
            byte* data = (byte*)(dstData.Scan0);
            //将图像转换为0,1二值得图像; 
            int step = dstData.Stride;
            for (int i = 0; i < dstData.Height; i++)
            {
                for (int j = 0; j < dstData.Width * 3; j += 3)
                {
                    if (data[i * step + j] > 128)
                        //如果是白线条，只要将0改成1，将1改成0
                        data[i * step + j]
                            = data[i * step + j + 1]
                            = data[i * step + j + 2]
                            = 0;
                    else
                        data[i * step + j]
                            = data[i * step + j + 1]
                            = data[i * step + j + 2]
                            = 1;
                }
            }

            BitmapData dstData1 = NImg.LockBits(new Rectangle(0, 0, iw, ih), ImageLockMode.ReadWrite, NImg.PixelFormat);
            byte* data1 = (byte*)(dstData1.Scan0);
            int step1 = dstData1.Stride;
            //细化循环开始           
            while (bModified)
            {
                bModified = false;
                //初始化临时二值图像NImg                
                for (int i = 0; i < dstData1.Height; i++)
                {
                    for (int j = 0; j < dstData1.Width * 3; j++)
                    {
                        data1[i * step1 + j] = 0;
                    }
                }
                for (int i = 2; i < ih - 2; i++)
                {
                    for (int j = 6; j < iw * 3 - 6; j += 3)
                    {
                        bCondition1 = false;
                        bCondition2 = false;
                        bCondition3 = false;
                        bCondition4 = false;
                        if (data[i * step + j] == 0)
                            //若图像的当前点为白色，则跳过                           
                            continue;
                        for (int k = 0; k < 5; k++)
                        {
                            //取以当前点为中心的5X5块                           
                            for (int l = 0; l < 5; l++)
                            {
                                //1代表黑色, 0代表白色                             
                                //neighbour[k, l] = bw[i + k - 2, j + l - 2];         
                                //neighbour[k, l] = data[(i + k - 2) * step + (j + l - 2)];
                                neighbour[k, l] = data[(i + k - 2) * step + (j + l * 3 - 6)];
                            }
                        }
                        //(1)判断条件2<=n(p)<=6          
                        nCount = neighbour[1, 1] + neighbour[1, 2] + neighbour[1, 3] + neighbour[2, 1] + neighbour[2, 3] + neighbour[3, 1] + neighbour[3, 2] + neighbour[3, 3];
                        if (nCount >= 2 && nCount <= 6)
                            bCondition1 = true;
                        else
                        {
                            data1[i * step1 + j] = 1;
                            continue;
                            //跳过, 加快速度                       
                        }
                        //(2)判断s(p)=1                      
                        nCount = 0;
                        if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1)
                            nCount++;
                        if (neighbour[1, 3] == 0 && neighbour[1, 2] == 1)
                            nCount++;
                        if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1)
                            nCount++;
                        if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1)
                            nCount++;
                        if (neighbour[2, 1] == 0 && neighbour[3, 1] == 1)
                            nCount++;
                        if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1)
                            nCount++;
                        if (neighbour[3, 2] == 0 && neighbour[3, 3] == 1)
                            nCount++;
                        if (neighbour[3, 3] == 0 && neighbour[2, 3] == 1)
                            nCount++;
                        if (nCount == 1)
                            bCondition2 = true;
                        else
                        {
                            data1[i * step1 + j] = 1;
                            continue;
                        }
                        //(3)判断p0*p2*p4=0 or s(p2)!=1   
                        if (neighbour[2, 3] * neighbour[1, 2] * neighbour[2, 1] == 0)
                            bCondition3 = true;
                        else
                        {
                            nCount = 0;
                            if (neighbour[0, 2] == 0 && neighbour[0, 1] == 1)
                                nCount++;
                            if (neighbour[0, 1] == 0 && neighbour[1, 1] == 1)
                                nCount++;
                            if (neighbour[1, 1] == 0 && neighbour[2, 1] == 1)
                                nCount++;
                            if (neighbour[2, 1] == 0 && neighbour[2, 2] == 1)
                                nCount++;
                            if (neighbour[2, 2] == 0 && neighbour[2, 3] == 1)
                                nCount++;
                            if (neighbour[2, 3] == 0 && neighbour[1, 3] == 1)
                                nCount++;
                            if (neighbour[1, 3] == 0 && neighbour[0, 3] == 1)
                                nCount++;
                            if (neighbour[0, 3] == 0 && neighbour[0, 2] == 1)
                                nCount++;
                            if (nCount != 1)
                                //s(p2)!=1                              
                                bCondition3 = true;
                            else
                            {
                                data1[i * step1 + j] = 1;
                                continue;
                            }
                        }
                        //(4)判断p2*p4*p6=0 or s(p4)!=1    
                        if (neighbour[1, 2] * neighbour[2, 1] * neighbour[3, 2] == 0)
                            bCondition4 = true;
                        else
                        {
                            nCount = 0;
                            if (neighbour[1, 1] == 0 && neighbour[1, 0] == 1)
                                nCount++;
                            if (neighbour[1, 0] == 0 && neighbour[2, 0] == 1)
                                nCount++;
                            if (neighbour[2, 0] == 0 && neighbour[3, 0] == 1)
                                nCount++;
                            if (neighbour[3, 0] == 0 && neighbour[3, 1] == 1)
                                nCount++;
                            if (neighbour[3, 1] == 0 && neighbour[3, 2] == 1)
                                nCount++;
                            if (neighbour[3, 2] == 0 && neighbour[2, 2] == 1)
                                nCount++;
                            if (neighbour[2, 2] == 0 && neighbour[1, 2] == 1)
                                nCount++;
                            if (neighbour[1, 2] == 0 && neighbour[1, 1] == 1)
                                nCount++;
                            if (nCount != 1)//s(p4)!=1       
                                bCondition4 = true;
                        }
                        if (bCondition1 && bCondition2 && bCondition3 && bCondition4)
                        {
                            data1[i * step1 + j] = 0;
                            bModified = true;
                        }
                        else
                        {
                            data1[i * step1 + j] = 1;
                        }
                    }
                }
                // 将细化了的临时图像bw_tem[w,h]copy到bw[w,h],完成一次细化   
                for (int i = 2; i < ih - 2; i++)
                    for (int j = 2; j < iw * 3 - 2; j++)
                        data[i * step + j] = data1[i * step1 + j];
            }
            for (int i = 2; i < ih - 2; i++)
            {
                for (int j = 6; j < iw * 3 - 6; j += 3)
                {
                    if (data[i * step + j] == 1)

                        data[i * step + j]
                            = data[i * step + j + 1]
                            = data[i * step + j + 2]
                            = 0;

                    else

                        data[i * step + j]
                            = data[i * step + j + 1]
                            = data[i * step + j + 2]
                            = 255;

                }
            }
            srcImg.UnlockBits(dstData);
            NImg.UnlockBits(dstData1);
            return (srcImg);
        }

    }
}
